package com.scl.yygh.common.result;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * 全局结果处理类
 * @author 超哥
 * @create 2021-07-01 14:51
 * ////////////////////////////////////////////////////////////////////
 * //                          _ooOoo_                               //
 * //                         o8888888o                              //
 * //                         88" . "88                              //
 * //                         (| ^_^ |)                              //
 * //                         O\  =  /O                              //
 * //                      ____/`---'\____                           //
 * //                    .'  \\|     |//  `.                         //
 * //                   /  \\|||  :  |||//  \                        //
 * //                  /  _||||| -:- |||||-  \                       //
 * //                  |   | \\\  -  /// |   |                       //
 * //                  | \_|  ''\---/''  |   |                       //
 * //                  \  .-\__  `-`  ___/-. /                       //
 * //                ___`. .'  /--.--\  `. . ___                     //
 * //              ."" '<  `.___\_<|>_/___.'  >'"".                  //
 * //            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
 * //            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
 * //      ========`-.____`-.___\_____/___.-`____.-'========         //
 * //                           `=---='                              //
 * //      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
 * //         佛祖保佑       永无BUG     永不修改                        //
 * ////////////////////////////////////////////////////////////////////
 * 佛曰:
 * 写字楼里写字间，写字间里程序员；
 * 程序人员写程序，又拿程序换酒钱。
 * 酒醒只在网上坐，酒醉还来网下眠；
 * 酒醉酒醒日复日，网上网下年复年。
 * 但愿老死电脑间，不愿鞠躬老板前；
 * 奔驰宝马贵者趣，公交自行程序员。
 * 别人笑我忒疯癫，我笑自己命太贱；
 * 不见满街漂亮妹，哪个归得程序员？
 */
@Data
@ApiModel(value = "全局统一返回结果")
public class Result<T> {

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private T data;

    /***
     * 无参构造器 用来New对象
     */
    public Result() {
    }

    /***
     * 返回空对象 供一些需要一个空对象的方法调用 目前不知道有什么用 先留着吧
     * @param <T>
     * @return result对象
     */
    public static <T> Result<T> build() {
        return new Result();
    }

    /***
     * 构造一个带数据的对象
     * @param data:要存储的对象
     * @param <T>:泛型
     * @return:返回一个带数据的result对象
     */
    protected static <T> Result<T> build(T data) {
        Result<T> result = new Result<T>();
        if (data != null) {
            result.setData(data);
        }
        return result;
    }

    /***
     * 构造一个 携带状态码以及消息的result对象
     * @param code 状态码
     * @param message 消息
     * @param <T>
     * @return result对象
     */
    protected static <T> Result<T> build(Integer code, String message) {
        Result<T> result = new Result<T>();
        if (code != null) {
            result.setCode(code);
        }
        if (message!=null){
            result.setMessage(message);
        }
        return result;
    }

    /***
     * 构造一个带数据以及携带状态码和消息的result对象（全属性）
     * @param body:需要携带的数据
     * @param resultCodeEnum:统一ResultCodeEnum对象 其中有Code和Message属性
     * @param <T>
     * @return result对象
     */
    protected static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }
    /************************ 以上方法为本类构建对象方法 不对外暴露 *****************************/

                        /*** 来自一个已经三天没睡好觉的程序员留下的彩蛋 ***/
                        /*** 心脏跳动和字节跳动总要二选一对吧 冲冲冲！ ***/
                        /*** 2021-07-21 ***/

    /************************ 以下方法为处理成功或失败结果 *****************************/
    public static <T> Result<T> ok() {
        return Result.ok(null);
    }

    /**
     * 操作成功
     *
     * @param data:需要返回的数据
     * @param <T>:返回泛型
     * @return:返回一个拥有全部属性的对象 其data属性值为传入的data Code为200 消息为成功
     */
    public static <T> Result<T> ok(T data) {
        return build(data, ResultCodeEnum.SUCCESS);
    }

    /***
     * 返回携带错误码以及错误信息的错误结果
     * [null,code,message]
     * 注：1. 该方法仅供全局异常处理类调用
     *    2. 其余所有错误结果 不得调用此方法 ****
     *    3. 需要和不需要任何数据的错误结果 都调用fail(T data)方法  根据参数是否为null进行区分
     *    4. 需要错误码和错误信息的错误结果，不需要数据 自行在ResultCodeEnum设置枚举值，然后调用failEnum(ResultCodeEnum codeEnum)方法
     *    5. 如果需要全部属性的错误结果 调用fail(T data,ResultCodeEnum codeEnum)方法 传入data和codeEnum即可
     * @param code 错误码
     * @param message 错误信息
     * @param <T>
     * @return 处理失败
     */
    public static <T> Result<T> fail(Integer code, String message) {
        return build(code, message);
    }

    /**
     * 返回带/不带数据的错误结果
     * 根据参数是否为null进行区分
     * [data，201，错误]
     *
     * @param data 数据信息
     * @return 处理失败
     */
    public static <T> Result<T> fail(T data) {
        if (data != null) {
            return build(data, ResultCodeEnum.FAIL);
        } else {
            return build(null, ResultCodeEnum.FAIL);
        }
    }

    /**
     * 返回全属性的错误结果 （可以自定义异常码和异常信息）
     * [data，codeEnum.getCode，codeEnum.getMessage]
     *
     * @param data 数据信息
     * @param codeEnum 错误信息枚举值
     * @return 处理失败
     */
    public static <T> Result<T> fail(T data, ResultCodeEnum codeEnum) {
        return build(data, codeEnum);
    }

    /***
     * 返回指定的错误码和错误信息的错误结果 可以所有方法调用
     * @param codeEnum 错误信息枚举值
     * @param <T>
     * @return 处理失败
     */
    public static <T> Result<T> failEnum(ResultCodeEnum codeEnum) {
        return build(null, codeEnum);
    }
}
